package image;

import com.lti.civil.*;
import com.lti.civil.awt.AWTImageConverter;
import common.ConstVars;

import java.awt.image.BufferedImage;
import java.util.List;

/**
 * WRITE A BETTER DESCRIPTION!
 *
 * @author Mike (mcchristensen@email.wm.edu)
 */
public class ImageCapturerImpl implements ImageCapturer {

    CaptureSystem system;
    CaptureStream captureStream;
    CaptureDeviceInfo info;
    MyCaptureObserver mco;
    boolean ready;
    double[] imageVector;

    public static void main(String[] args)
    {
        if(args.length < 1)
        {
          System.err.println("Need an argument!");
          System.exit(1);
        }
        ImageCapturerImpl ici = new ImageCapturerImpl();
        for(int i = 0;i < 10;i++)
        {
          double[] vector = ici.captureImageBoth("out" + args[0] + String.format("%04d", i) + ".jpg");
          System.out.println("image " + i + " captured");
          for(int x = 0;x < vector.length;x++)
            System.out.println(vector[x]);
          try
          {
            Thread.sleep(2000);
          }
          catch(Exception e){}
        }
    }

    public ImageCapturerImpl()
    {
        try {
              CaptureSystemFactory factory = DefaultCaptureSystemFactorySingleton.instance();
              system = factory.createCaptureSystem();
              system.init();
              List list = system.getCaptureDeviceInfoList();

              if(list.size() < 1)
              {
                System.out.println("No camera device found.  Giving up...");
                System.exit(1);
              }
              info  = (CaptureDeviceInfo) list.get(0);
              System.out.println("Device ID: " + info.getDeviceID());
              System.out.println("Description: " + info.getDescription());
        }
        catch(Exception e) {
            System.out.println(e);
        }
    }

    private void startCaptureStream(String fileName, boolean saveVector)
    {
        ready = false;
        try
        {
            if(captureStream == null){
                captureStream = system.openCaptureDeviceStream(info.getDeviceID());
                mco = new MyCaptureObserver(this, fileName, saveVector);
                captureStream.setObserver(mco);
                captureStream.start();
            }
            else {
                mco.setOutput(fileName, saveVector);
            }
        }
        catch(CaptureException e)
        {
            System.out.println(e);
        }
    }

    public void captureImage(String fileName)
    {
        startCaptureStream(fileName, false);
        while(!ready) {
            try {
                Thread.sleep(100);
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    }

    public double[] captureImage()
    {
      startCaptureStream(null, true);

      imageVector = new double[ConstVars.IMG_DIM_2];

      while(!ready) {
          try{
              Thread.sleep(100);
          } catch(Exception e){}
      }
      return imageVector;
    }

    public double[] captureImageBoth(String fileName)
    {
      startCaptureStream(fileName, true);

      imageVector = new double[ConstVars.IMG_DIM_2];

      while(!ready) {
          try{
              Thread.sleep(100);
          } catch(Exception e){}
      }
      return imageVector;
    }

    protected void saveImage(Image image, String fileName, boolean saveVector)
    {
        BufferedImage bimage = AWTImageConverter.toBufferedImage(image);

        if(fileName != null)
        {
            ImageFixer.save(bimage, fileName);
        }

        if(saveVector)
        {
            bimage = ImageFixer.resizeImage(bimage, ConstVars.IMG_DIM, ConstVars.IMG_DIM);
            ImageFixer.toGray(bimage);
            ImageFixer.imageToVector(bimage, imageVector);
        }
        ready = true;
        mco.stopOutput();
    }
}

class MyCaptureObserver implements CaptureObserver
{
    private ImageCapturer parent;
    String fileName;
    boolean saveVector;

    protected MyCaptureObserver(ImageCapturer parent, String fileName, boolean saveVector)
    {
        super();
        this.parent = parent;
        this.fileName = fileName;
        this.saveVector = saveVector;
    }

    public void onError(CaptureStream sender, CaptureException e)
    {
        System.err.println("onError " + sender);
        e.printStackTrace();
    }

    public void onNewImage(CaptureStream sender, Image image)
    {
        if(fileName == null && saveVector == false) return;
        ((ImageCapturerImpl)parent).saveImage(image, fileName, saveVector);
    }

    public void setOutput(String fileName, boolean saveVector)
    {
        this.fileName = fileName;
        this.saveVector = saveVector;
    }

    public void stopOutput()
    {
        fileName = null;
        saveVector = false;
    }
}
